#include "createREF2.h"
#include "legoland.h"
#include "frequency.h"
#include "kmeans.h"
#include <unistd.h>
#define GetCurrentDir _getcwd
#include <iostream>
#include <fstream>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <time.h>

using namespace std;

bool file_exists(char * file_name);
bool correct_format(char * file_name);

/*************************************************************************
* CreateREF - constructor
*   Sets up initial parameter values. Makes calls to retieve all
*   parameters and verifies that files exist.
**************************************************************************/
CreateREF2::CreateREF2()
{
    system("CLS");
    cout    << "Create a Reference File for DISCO\n\n";

    gc_dim1 = 25;
    gc_dim2 = 75;

    char *path = NULL;
    path = getcwd(NULL, 0); // or _getcwd
    if ( path != NULL)
        printf("%s\n", path);


    gc_dim1_file=new char [500];
    gc_dim2_file=new char [500];
    sprintf(gc_dim1_file,"%s/GC_axis/GC%d%s", path, gc_dim1, ".ref");
    sprintf(gc_dim2_file,"%s/GC_axis/GC%d%s", path, gc_dim2, ".ref");

    cout << gc_dim1_file << endl;

    if(get_parameters())
    {
        /**
        eliminated this error checking step because of elmination of fof, no need since libraries are now created directly from
        individual fasta files, some file checking is included later in the process but should be improved and addition of FASTQ
        support should be re-added.
        **/
//        if(!load_taxa())
//        {
//            cout << "There is a problem with the reference set file. Please check this file and the DISCO documentation.\n";
//            cout << "The library was not created." << endl;
//        }
//        else
//        {
            if(!create_reference_library())
            {
                cout << "An error occurred during the creation of the library.\n";
                cout << "Please verify that the reference set file is correct.\n";
                cout << "The library was not created." << endl;
            }
            cout << "The reference library " << output_file_name << " was created." << endl;
//        }
    }
    else
        cout << "The parameters were not set correctly. No library was created." << endl;

    char r;
    cout << "press ENTER to continue";
    cin >> r;
}

/*************************************************************************
* CreateREF - deconstructor
*   deletes all dynamically allocated memory class variables
**************************************************************************/
CreateREF2::~CreateREF2()
{
    int i;
    reference_file = NULL;
    delete reference_file;
    output_file_name = NULL;
    delete output_file_name;
    for(i=0; i<num_gs; i++)
    {
        taxa[i] = NULL;
        delete taxa[i];
    }
    taxa = NULL;
    delete taxa;
    gc_dim1_file = NULL;
    delete gc_dim1_file;
    gc_dim2_file = NULL;
    delete gc_dim2_file;
}

/*************************************************************************
* create_reference_library
*   Performs frequency k-mer counts, reduces to axes, clusters,
*   and writes out results. l is instantiated in this function

Mike: changed to work for only creating one library from one genome
legoland therefore removed and only "centroids" are created from
frequency plots
**************************************************************************/
bool CreateREF2::create_reference_library()
{
    int multiplier = 1;
    /**
    removed because of elimination of multipler from creation of genome libraries,  by moving the multiplier out of here (setting it to 1)
    and adding it upon the creation of merged libraries there is one less variable that is required to be identical to allow libraries to
    be merged
    **/
//    if(!use_default_LLmult)
//    {
//        cout << "Please enter the mapping multiplier you wish to use. Refer to documentation for\n";
//        cout << "further information regaurding this variable. Value: ";
//        cin >> multiplier;
//        if(multiplier<=0) {cout << "This is not a valid value. The default will be used." << endl; use_default_LLmult=true;}
//    }
    bool thing = true;
    while (thing == true)
    {
        cout << "Please refer to documentation re: the formatting of reference set files." << endl;
        cout << "Please enter the file listing the genome to be included in the referenceor q to exit:\n";
        reference_file=new char [300];
        cin >> reference_file;
        output_file_name = reference_file;

//        char *path = NULL;
    //    path = getcwd(NULL, 0); // or _getcwd
        if( (reference_file[0]=='Q' || reference_file[0]=='q') && (strlen(reference_file)==1) )
        {
                cout << "Goodbye" << endl;
                thing = false;
                break;
                delete reference_file;
        }

        int i,j;
        int num_coordinates;
    //    coordinates * c;
    //    kmeans * clusters;
    //    centroid * plot;
//        vector<centroid> plot;
//        legoland ** l=new legoland * [k_max-k_min+1];
        vector<centroid> * c = new vector<centroid> [k_max-k_min+1];
    //    int kum=read_size;
        Profile * p;


    //    int kum = multiplier*2;

        for(i=0; i<=k_max-k_min; i++)
        {
            p=new Profile(k_min+i,read_size,gc_dim1_file,gc_dim2_file);

//            if(!use_default_LLmult) l[i]=new legoland(multiplier);
//            else l[i]=new legoland();
//            plot.clear();
            num_coordinates=p->get_centroids_genome(reference_file,c[i]);  //changed from c to plot and get coords to get centroids

            if(num_coordinates==0)
            {
//                delete c;
                j=num_gs;
                i=k_max;
            }
            cout << num_coordinates << " centroids generated, adding to legoland" << endl;
//            l[i]->add(plot,num_coordinates);                      //map to legoland  //changed plot since not using kmeans
//            plot.clear();
            p = NULL;
            delete p;
//            l[i]->printLegoland();
        }
        if(num_coordinates==0)
        {
//            cout << "in this loop?" << endl;
//            for(i=0; i<k_max-k_min+1; i++)
//                delete l[i];
//            delete l;
            break;
        }

        //write out to file
        ofstream out;
        char file[300];
        sprintf(file,"%s_disco.lib",output_file_name);
        out.open(file);
        if (!out.is_open())
        {
            cout << "library destination file not opened" << endl;
            return false;
        }
        cout << "file opened" << endl;
        out << k_min << "\t" << k_max << endl;
        out << gc_dim1 << "\t" << gc_dim2 << endl;
        out << read_size << endl;
        /**
        formatting changes, elminating multiplier and taxa as new format has no multiplier,and only one taxa
        TODO: taxa should be named and name should be in this file so can be used when merging multiple files
        **/
//        out << l[i-1]->get_multiplier() << endl;
    //    out << num_gs << endl;
    //    for(i=0; i<num_gs-1; i++)
    //        out << taxa[i] << "\t";
    //    out << taxa[i] << endl;
    //    out << "*" << endl;
        vector<lego> v;
    //    unsigned long long ii;
        for(i=0; i<=k_max-k_min; i++)
        {
            /**
            more formatting changes to accomate change from multiple file to single file library
            **/
//            for(int x=0; x<multiplier+1; x++)
//            {
//                for (int y=0; y<multiplier+1; y++)
//                {
//                    v=l[i]->search(x,y);
//                    if(v.size()!=0)
//                    {
//                        out << x << "\t" << y << "\t" << v.size() << "\t";
//                        for(j=0; j<v.size()-1; j++)
//                            out << v[j].taxon << "\t" << v[j].prob << "\t";
//                        out << v[j].taxon << "\t" << v[j].prob << endl;
//                    }
//                }
//            }
    //        l[i]->printLegoland();
            for (int j = 0; j < c[i].size(); j++)
            {
                out << c[i][j].x << "\t" << c[i][j].y << "\t" << c[i][j].prob*1000000000 << endl;   //*1000000000 is a random multiplier used to eliminate sci. notation in output
            }
            out << "*" << endl;
//            cout << "about to delete l[i]" << endl;
//            l[i] = NULL;
//            delete l[i];
//            cout << "l[i] deleted" << endl;           //cleaning memory as i write
        }
        out.clear();
        out.close();


        //clean up memory
//        l = NULL;
//        delete l;
        delete reference_file;
    }
    return true;
}

/*************************************************************************
* get_parameters
*   Asks user for the basic parameters
**************************************************************************/
bool CreateREF2::get_parameters()
{
    char selection;
    bool get_ks=true;

    if(!file_exists(gc_dim1_file) || !file_exists(gc_dim2_file))
    {
        cout << "Please check that the corresponding files are in the folder\nlabeled GC_axis\n";
        return false;
    }
    cout << "Got to get_parameters" << endl;

/**
eliminated with fof
**/
//    if(get_reference_file())
//    {
        while(get_ks)
        {
            cout<<"Enter new min k-mer size: ";
            cin>>k_min;
            cout<<"Enter new max k-mer size (Maximum 9): ";
            cin>>k_max;
            if(k_max>9) k_max=9;
            if(k_max>=k_min) get_ks=false;
            else
            {
                cout << "The k-mer minimum size must be less than the k-mer maximum size." << endl;
                cout << "Try again.\n\n";
            }
        }

        cout << "Please enter the length of the read: " << endl;
        cin >> read_size;

/**
moved to loop to facilitate making multiple reference files from multiple genomes with identical parameters
probably should be more changes for error checking and optimization
**/
//        output_file_name=new char [300];
//        cout << "Enter the name for the library file to be written (no file extension):\n";
//        cin >> output_file_name;

        cout << "Do you wish to set the advanced parameters? ";
        cin>> selection;
        if(selection=='y' || selection=='Y')
        {
            if(get_advanced_parameters())
                return true;
        }
        else return true;
//    }
    return false;
}

/*************************************************************************
* get_advanced_parameters
*   Gets the advanced parameters including:
*       - the mapping multiplier
*       - the axes
*   returns true unless the GC files are missing
**************************************************************************/
bool CreateREF2::get_advanced_parameters()
{
    //changes GC content references
    char selection;
    int temp_gc_dim1, temp_gc_dim2;
    cout << endl;
    cout    << "Advanced Parameters: \n\n";

    cout << "Do you wish to use the default mapping multiplier? (Y-recommended or N) : ";
    cin>>selection;
    if(selection=='N') use_default_LLmult=false;

    cout << endl;
    cout << "Read compositions will be mapped to synthetic genomes of GC content ";
    cout << gc_dim1 << " & " << gc_dim2 << "." << endl << endl;
    cout << "Do you wish to change these? (Y/N) ";
    cin>>selection;
    if(selection>96) selection-=32;

    if(selection=='Y')
    {
        cout << "Axes can be of a GC between 25 and 75%, multiples of 5.\n";
        cout << "New GC content axis 1: ";
        cin >> temp_gc_dim1;
        while( (temp_gc_dim1%5!=0) && (temp_gc_dim1>=25 && temp_gc_dim1<=75) )
        {
            cout << "Axes can be of a GC between 25 and 75%, multiples of 5.\n";
            cout << "New GC content axis 1: ";
            cin >> temp_gc_dim1;
        }
        cout << "New GC content axis 2: ";
        cin >> temp_gc_dim2;
        while( (temp_gc_dim2%5!=0) && (temp_gc_dim2>=25 && temp_gc_dim2<=75) )
        {
            cout << "Axes can be of a GC between 25 and 75%, multiples of 5.\n";
            cout << "New GC content axis 2: ";
            cin >> temp_gc_dim2;
        }
        cout << "Do you wish to make these changes? (Y/N) ";
        cin>>selection;
        if(selection>96) selection-=32;
        if(selection=='Y')
        {
            gc_dim1=temp_gc_dim1;
            gc_dim2=temp_gc_dim2;
            sprintf(gc_dim1_file,"~/GC_axis/%d.ref",gc_dim1);
            sprintf(gc_dim2_file,"~/GC_axis/%d.ref",gc_dim2);
            if(!file_exists(gc_dim1_file) || !file_exists(gc_dim2_file))
            {
                cout << "Please check that the corresponding files are in the folder\nlabeled GC_axes\n";
                return false;
            }
        }
    }
    else
    {
        cout << "No changes will be made." << endl;
    }
    return true;
}

/*************************************************************************
* correct_format
*   Prompts user for the reference file. User can quit (return false).
**************************************************************************/
bool CreateREF2::get_reference_file()
{
//    string filename (reference_file);
//    output_file_name = filename.substr(0,9).c_str();
//    strcat(path,user_ref_file);
//    reference_file = path;

    cout << "Please enter the length of the read: " << endl;
    cin >> read_size;

    cout << "Looking for: " << reference_file << endl;
    if(!file_exists(reference_file))            //Maybe use a while loop here? while(!file_exists(reference_file)
    {
        cout << "This file does not exist. Please try again.\n";
        cout << "Please enter the file listing the genomes to be included in the reference or type Q to exit:\n";
        cin >> reference_file;
//        strcat(path,reference_file);
//        reference_file = path;
        if( (reference_file[0]=='Q' || reference_file[0]=='q') && (strlen(reference_file)==1) )
        {
            cout << "Goodbye" << endl;
            return false;
        }
    }
    cout << "About to check format of reference file" << endl;
    if(correct_format(reference_file))
        return true;
    else
        return false;
}

//CreateREF2::merge()
//{
//
//}

///////////////////////////// LOCAL VARIABLES /////////////////////////////

/*************************************************************************
* correct_format
*   parameters:
*       -file_name:     file name of the taxa/genome file list
*   returns true if in the right format, else false
**************************************************************************/
bool CreateREF2::correct_format(char * file_name)
{
    char line[500];
    ifstream in;
    in.open(file_name);
    if(!in.is_open())
    {
        cout << "file not open" << endl;
        return false;}
    cout << "Found File for formatting" << endl;
    char i;
    in >> i;
    if (i!='>')
    {
        cout << "file in wrong format try again" << endl;
    }
    in.clear();
    in.close();
    cout << "Finished checking format and its correct" << endl;
    return true;
}

/*************************************************************************
* file_exist - determines if a file exists
*   parameters:
*       -file_name: name of file you are checking if it exists
*   return: true if file exists else false
**************************************************************************/
bool CreateREF2::file_exists(char * file_name)
{
    ifstream in;
    in.open(file_name);
    if(in.is_open())
    {
        in.clear();
        in.close();
        return true;
    }
    else
        return false;
}
